package com.ruoyi.project.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.ruoyi.common.utils.PicUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.common.StaticField;
import com.ruoyi.project.service.CloudOssService;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author abel lee
 * @create 2020-07-10 13:01
 **/
@Service("TenantCloudOssServiceImpl")
public class TenantCloudOssServiceImpl implements CloudOssService {
    private static Logger logger = LoggerFactory.getLogger(TenantCloudOssServiceImpl.class.getName());

    private String secretId = "";
    private String secretKey = "";
    private String regionName = "";
    private String bucketName = "";
    private String qCloudPrefix = "";

    @Override
    public String uploadFile(MultipartFile file, boolean compress) {
        // 1 初始化用户身份信息（secretId, secretKey）。

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
// 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        // https://commission-1302479539.cos.ap-chengdu.myqcloud.com/1dc972e062ce65a7f2a22d60edb5ee25.jpg
        try {
            InputStream fileContent = null;
            String fileName = file.getOriginalFilename();
            String fileExt = "jpg";
            if(!StringUtils.equals("blob",fileName)){
                fileExt = fileName.substring(fileName.lastIndexOf("."));
            }
            String contentType = contentType(fileExt);
            fileContent = file.getInputStream();
            logger.info("file size--->"+fileContent.available());
            if(contentType.startsWith("image") && compress){
                if(fileContent.available()>2000*1024){
                    String tempPath =System.getProperty("java.io.tmpdir")+File.separator;
                    File srcFile = new File(tempPath, UUID.randomUUID().toString()+"."+fileExt);
                    file.transferTo(srcFile);
                    File targetFile =  new File(tempPath,UUID.randomUUID().toString()+"target."+fileExt);
                    PicUtils.compressPicForScale(srcFile,targetFile,150,0.8,720);
                    fileContent = new FileInputStream(targetFile);
                }
            }

            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据，存在内存OOM的情况
            objectMetadata.setContentLength(fileContent.available());
            // 默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
            objectMetadata.setContentType(file.getContentType());
            // 指定要上传到的存储桶
            // 指定要上传到 COS 上对象键
            if(StringUtils.equals(fileName,"blob")){
                fileName = "blog.jpg";
            }
            int lastIndex = fileName.lastIndexOf('.');
            String key = fileName.substring(0,lastIndex) + "-" + System.currentTimeMillis() + fileName.substring(lastIndex);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, fileContent, objectMetadata);
            cosClient.putObject(putObjectRequest);
            return ""+key;
        } catch (CosServiceException serverException) {
            serverException.printStackTrace();
        } catch (CosClientException clientException) {
            clientException.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            cosClient.shutdown();
        }
        return "";
    }


    public static String contentType(String filenameExtension) {
        if (filenameExtension.equals(".BMP") || filenameExtension.equals(".bmp")) {
            return "image/bmp";
        }
        if (filenameExtension.equals(".GIF") || filenameExtension.equals(".gif")) {
            return "image/gif";
        }
        if (filenameExtension.equals(".PDF") || filenameExtension.equals(".pdf")) {
            return "application/pdf";
        }
        if (filenameExtension.equals(".JPEG") || filenameExtension.equals(".jpeg") ||
                filenameExtension.equals(".JPG") || filenameExtension.equals(".jpg") ||
                filenameExtension.equals(".PNG") || filenameExtension.equals(".png")) {
            return "image/jpeg";
        }
        if (filenameExtension.equals(".HTML") || filenameExtension.equals(".html")) {
            return "text/html";
        }
        if (filenameExtension.equals(".TXT") || filenameExtension.equals(".txt")) {
            return "text/plain";
        }
        if (filenameExtension.equals(".VSD") || filenameExtension.equals(".vsd")) {
            return "application/vnd.visio";
        }
        if (filenameExtension.equals(".PPTX") || filenameExtension.equals(".pptx") ||
                filenameExtension.equals(".PPT") || filenameExtension.equals(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (filenameExtension.equals(".DOCX") || filenameExtension.equals(".docx") ||
                filenameExtension.equals(".DOC") || filenameExtension.equals(".doc")) {
            return "application/msword";
        }
        if (filenameExtension.equals(".XML") || filenameExtension.equals(".xml")) {
            return "text/xml";
        }
        if (filenameExtension.equals(".mp4") || filenameExtension.equals(".m3u8")) {
            return "video/mp4";
        }
        return "text/html";
    }

    @Override
    public String getQCloudUrl() {
        return qCloudPrefix;
    }

    public void downloadFile(String key, HttpServletResponse response) throws IOException {
        // Bucket的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
// 方法1 获取下载输入流
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
// 限流使用的单位是 bit/s, 这里设置下载带宽限制为10MB/s
        getObjectRequest.setTrafficLimit(80*1024*1024);
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
// 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        COSObject cosObject = cosClient.getObject(getObjectRequest);
        COSObjectInputStream cosObjectInput = cosObject.getObjectContent();
        // 从阿里云进行下载 http://blog.csdn.net/qq_35498405/article/details/77942817
        // 缓冲文件输出流
        BufferedOutputStream outputStream=new BufferedOutputStream(response.getOutputStream());
        // 通知浏览器以附件形式下载
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(key,"UTF-8"));
        // 进行解码 为防止文件出现乱码 文件上传时进行编码处理
        Base64.Decoder base64Decoder = Base64.getDecoder();
        byte[] car=new byte[1024];
        int L=0;
        while((L=cosObjectInput.read(car))!=-1){
            car =  base64Decoder.decode(IOUtils.toByteArray(cosObjectInput));
            //L 如果不给长度会有文件损坏
            outputStream.write(car, 0,L);
        }
        if(outputStream!=null){
            outputStream.flush();
            outputStream.close();
        }
        cosClient.shutdown();
    }

    @Override
    public String uploadFile(File file) {
        // 1 初始化用户身份信息（secretId, secretKey）。

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
// 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        // https://commission-1302479539.cos.ap-chengdu.myqcloud.com/1dc972e062ce65a7f2a22d60edb5ee25.jpg
        try {
            InputStream fileContent = null;
            String fileName = file.getName();
            String fileExt = fileName.substring(fileName.lastIndexOf("."));
            String contentType = contentType(fileExt);
            fileContent = new FileInputStream(file);
            logger.info("file size--->"+fileContent.available());

            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据，存在内存OOM的情况
            objectMetadata.setContentLength(fileContent.available());
            // 默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
            objectMetadata.setContentType(contentType);
            // 指定要上传到的存储桶
            // 指定要上传到 COS 上对象键
            if(StringUtils.equals(fileName,"blob")){
                fileName = "blog.jpg";
            }
            int lastIndex = fileName.lastIndexOf('.');
            String key = fileName.substring(0,lastIndex) + "-" + System.currentTimeMillis() + fileName.substring(lastIndex);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, fileContent, objectMetadata);
            cosClient.putObject(putObjectRequest);
            return ""+key;
        } catch (CosServiceException serverException) {
            serverException.printStackTrace();
        } catch (CosClientException clientException) {
            clientException.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            cosClient.shutdown();
        }
        return "";
    }

    public String uploadFile(InputStream fileContent,String fileExt) {
        // 1 初始化用户身份信息（secretId, secretKey）。

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
// 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        // https://commission-1302479539.cos.ap-chengdu.myqcloud.com/1dc972e062ce65a7f2a22d60edb5ee25.jpg
        try {
            String key = com.ruoyi.common.utils.uuid.UUID.fastUUID().toString(true)+fileExt;
            String contentType = contentType(fileExt);
            logger.info("file size--->"+fileContent.available());
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据，存在内存OOM的情况
            objectMetadata.setContentLength(fileContent.available());
            // 默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
            objectMetadata.setContentType(contentType);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, fileContent, objectMetadata);
            cosClient.putObject(putObjectRequest);
            return ""+key;
        } catch (CosServiceException serverException) {
            serverException.printStackTrace();
        } catch (CosClientException clientException) {
            clientException.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            cosClient.shutdown();
        }
        return "";
    }

    @Override
    public void downloadFile(String key, File file) throws IOException {
        // Bucket的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
// 方法1 获取下载输入流
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
// 限流使用的单位是 bit/s, 这里设置下载带宽限制为10MB/s
        getObjectRequest.setTrafficLimit(80*1024*1024);
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
// 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        ObjectMetadata  cosObject = cosClient.getObject(getObjectRequest,file);
        cosClient.shutdown();
    }

}
